/*
 *
 *  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 *  * openFuyao is licensed under Mulan PSL v2.
 *  * You can use this software according to the terms and conditions of the Mulan PSL v2.
 *  * You may obtain a copy of Mulan PSL v2 at:
 *  *          http://license.coscl.org.cn/MulanPSL2
 *  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 *  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 *  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *  * See the Mulan PSL v2 for more details.
 *
 */

// package ray config
package ray

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

	"openfuyao-rayservice/pkg/utils/httputil"

	"github.com/emicklei/go-restful/v3"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

// 创建 Operation 接口的模拟实现
type MockOperation struct {
	mock.Mock
}

func (m *MockOperation) MethodInitOperation() {
	m.Called()
}

func (m *MockOperation) MethodAllOverview() (*httputil.ResponseJson, int) {
	args := m.Called()
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}

func (m *MockOperation) MethodListMetaCrd(crd string) (*httputil.ResponseJson, int) {
	args := m.Called(crd)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}

func (m *MockOperation) MethodListCrd(crd string, req *CrdListRequest) (*httputil.ResponseJson, int) {
	args := m.Called(crd, req)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}

func (m *MockOperation) MethodCreateCrd(crd, data, createBy string, isStart bool) (*httputil.ResponseJson, int) {
	args := m.Called(crd, data, createBy, isStart)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}

func (m *MockOperation) MethodDeleteCrd(crd, ns, name string) (*httputil.ResponseJson, int) {
	args := m.Called(crd, ns, name)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}
func (m *MockOperation) MethodUpdateCrd(crd, ns, data, name string) (*httputil.ResponseJson, int) {
	args := m.Called(crd, ns, data, name)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}
func (m *MockOperation) MethodGetCrd(crd, ns, name string) (*httputil.ResponseJson, int) {
	args := m.Called(crd, ns, name)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}

func (m *MockOperation) MethodRestartCrd(crd, ns, name string) (*httputil.ResponseJson, int) {
	args := m.Called(crd, ns, name)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}

func (m *MockOperation) MethodStopCrd(crd, ns, name string) (*httputil.ResponseJson, int) {
	args := m.Called(crd, ns, name)
	return args.Get(0).(*httputil.ResponseJson), args.Int(1)
}

// 测试 GET 方法
func TestHandler_GET_Methods(t *testing.T) {
	// 在测试中注册路由的部分，需要与源代码中的函数保持一致
	// 创建一个新的 Handler 和 Container
	// 创建一个新的 MockOperation
	mockOp := new(MockOperation)
	handler := newHandler(mockOp)

	// 注册路由 - 使用与ConfigVolcano函数相同的方式
	ws := NewWebSevice(groupVersion)

	// 添加GET信息相关路由
	getInfoAddToContainer(ws, handler)

	tests := []struct {
		name           string
		path           string
		setupMock      func(mockOp *MockOperation)
		expectedStatus int
		expectedBody   map[string]interface{}
	}{
		{
			name: "Test_CrdGetGet",
			path: "/rest/v1/raycluster/get/vcjob/raycluster-autoscaler-1",
			setupMock: func(mockOp *MockOperation) {
				mockOp.On("MethodGetCrd", "raycluster", "vcjob", "raycluster-autoscaler-1").Return(
					&httputil.ResponseJson{
						Data: map[string]interface{}{"name": "raycluster-autoscaler-1"},
						Msg:  "success",
					},
					200,
				)
			},
			expectedStatus: 200,
			expectedBody: map[string]interface{}{
				"data": map[string]interface{}{"name": "raycluster-autoscaler-1"},
				"msg":  "success",
			},
		},
		{
			name: "Test_CrdListMetaGet",
			path: "/rest/v1/raycluster/list/meta",
			setupMock: func(mockOp *MockOperation) {
				mockOp.On("MethodListMetaCrd", "raycluster").Return(
					&httputil.ResponseJson{
						Data: map[string]interface{}{"name": "raycluster"},
						Msg:  "success",
					},
					200,
				)
			},
			expectedStatus: 200,
			expectedBody: map[string]interface{}{
				"data": map[string]interface{}{"name": "raycluster"},
				"msg":  "success",
			},
		},
		{
			name: "Test_OverviewAllGet",
			path: "/rest/v1/overview/all",
			setupMock: func(mockOp *MockOperation) {
				mockOp.On("MethodAllOverview").Return(
					&httputil.ResponseJson{
						Data: map[string]interface{}{"name": "all"},
						Msg:  "success",
					},
					200,
				)
			},
			expectedStatus: 200,
			expectedBody: map[string]interface{}{
				"data": map[string]interface{}{"name": "all"},
				"msg":  "success",
			},
		},
		{
			name: "Test_CrdListGet",
			path: "/rest/v1/raycluster/list",
			setupMock: func(mockOp *MockOperation) {
				mockOp.On("MethodListCrd", "raycluster", &CrdListRequest{}).Return(
					&httputil.ResponseJson{
						Data: map[string]interface{}{"name": "raycluster"},
						Msg:  "success",
					},
					200,
				)
			},
			expectedStatus: 200,
			expectedBody: map[string]interface{}{
				"data": map[string]interface{}{"name": "raycluster"},
				"msg":  "success",
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// 创建一个新的 MockOperation
			mockOp := new(MockOperation)

			// 设置 mock 的预期行为
			tt.setupMock(mockOp)

			// 创建一个新的 Handler 和 Container
			handler := newHandler(mockOp)
			container := restful.NewContainer()

			// 注册路由
			ws := NewWebSevice(groupVersion)

			// 添加路由 - 这里需要根据实际情况选择相应的方法
			getInfoAddToContainer(ws, handler)

			// 其他需要测试的路由...
			container.Add(ws)

			// 创建一个测试请求
			req := httptest.NewRequest("GET", tt.path, nil)
			req.Header.Set("Accept", restful.MIME_JSON) // 设置 Accept 头，解决 406 问题

			t.Logf("已注册的路由:")
			for _, route := range ws.Routes() {
				t.Logf("- %s %s", route.Method, route.Path)
			}

			// 然后对每个测试用例，打印完整的请求路径
			t.Logf("发送请求: %s %s", "GET", tt.path)

			// 创建一个 ResponseRecorder 来记录响应
			w := httptest.NewRecorder()

			// 发送请求
			container.ServeHTTP(w, req)

			// 验证状态码
			assert.Equal(t, tt.expectedStatus, w.Code, "状态码应该匹配")

			// 解析响应体
			var responseBody map[string]interface{}
			err := json.Unmarshal(w.Body.Bytes(), &responseBody)
			assert.NoError(t, err, "应该能够解析 JSON")

			// 验证响应体
			assert.Equal(t, tt.expectedBody, responseBody, "响应体应该匹配")

			// 验证 mock 预期已满足
			mockOp.AssertExpectations(t)
		})
	}
}

func TestHandler_POST_Methods(t *testing.T) {
	mockOp := new(MockOperation)
	handler := newHandler(mockOp)

	ws := NewWebSevice(groupVersion)

	getInfoAddToContainer(ws, handler)

	tests := []struct {
		name           string
		path           string
		requestBody    map[string]string
		formFile       map[string][]string
		setupMock      func(mockOp *MockOperation)
		expectedStatus int
		submitType     string
		expectedBody   map[string]interface{}
	}{
		{
			name: "Test_CrdCreatePost",
			path: "/rest/v1/raycluster/create",
			formFile: map[string][]string{
				"createBy": {"createBy"},
				"isStart":  {"false"},
				"config":   {"fileString"},
			},
			submitType: "form",
			setupMock: func(mockOp *MockOperation) {
				mockOp.On("MethodCreateCrd", "raycluster", "fileString", "createBy", false).Return(
					&httputil.ResponseJson{
						Data: map[string]interface{}{"name": "raycluster"},
						Msg:  "success",
					},
					200,
				)
			},
			expectedStatus: 200,
			expectedBody: map[string]interface{}{
				"data": map[string]interface{}{"name": "raycluster"},
				"msg":  "success",
			},
		},
		{
			name: "Test_CrdRestartPost",
			path: "/rest/v1/raycluster/restart/vcjob/raycluster-autoscaler-1",
			requestBody: map[string]string{
				"name": "raycluster",
			},
			submitType: "body",
			setupMock: func(mockOp *MockOperation) {
				mockOp.On("MethodRestartCrd", "raycluster", "vcjob", "raycluster-autoscaler-1").Return(
					&httputil.ResponseJson{
						Data: map[string]interface{}{"name": "raycluster"},
						Msg:  "success",
					},
					200,
				)
			},
			expectedStatus: 200,
			expectedBody: map[string]interface{}{
				"data": map[string]interface{}{"name": "raycluster"},
				"msg":  "success",
			},
		},
		{
			name: "Test_CrdStopPost",
			path: "/rest/v1/raycluster/stop/vcjob/raycluster-autoscaler-1",
			requestBody: map[string]string{
				"name": "raycluster",
			},
			submitType: "body",
			setupMock: func(mockOp *MockOperation) {
				mockOp.On("MethodStopCrd", "raycluster", "vcjob", "raycluster-autoscaler-1").Return(
					&httputil.ResponseJson{
						Data: map[string]interface{}{"name": "raycluster"},
						Msg:  "success",
					},
					200,
				)
			},
			expectedStatus: 200,
			expectedBody: map[string]interface{}{
				"data": map[string]interface{}{"name": "raycluster"},
				"msg":  "success",
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// 创建一个新的 MockOperation
			mockOp := new(MockOperation)

			// 设置 mock 的预期行为
			tt.setupMock(mockOp)

			// 创建一个新的 Handler 和 Container
			handler := newHandler(mockOp)
			container := restful.NewContainer()

			// 注册路由
			ws := NewWebSevice(groupVersion)

			// 添加路由 - 这里需要根据实际情况选择相应的方法
			getInfoAddToContainer(ws, handler)

			// 其他需要测试的路由...
			container.Add(ws)

			var err error
			var req *http.Request

			if tt.submitType == "body" {
				requestBodyJSON, err := json.Marshal(tt.requestBody)
				assert.NoError(t, err, "JSON 序列化不应失败")
				// 创建一个测试请求
				req = httptest.NewRequest("POST", tt.path, bytes.NewBuffer(requestBodyJSON))
				req.Header.Set("Content-Type", restful.MIME_JSON)
				req.Header.Set("Accept", restful.MIME_JSON)
			} else {
				req = httptest.NewRequest("POST", tt.path, strings.NewReader(url.Values(tt.formFile).Encode()))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			}

			// 创建一个 ResponseRecorder 来记录响应
			w := httptest.NewRecorder()

			// 发送请求
			container.ServeHTTP(w, req)

			// 验证状态码
			assert.Equal(t, tt.expectedStatus, w.Code, "状态码应该匹配")

			// 解析响应体
			var responseBody map[string]interface{}
			err = json.Unmarshal(w.Body.Bytes(), &responseBody)
			assert.NoError(t, err, "应该能够解析 JSON")

			// 验证响应体
			assert.Equal(t, tt.expectedBody, responseBody, "响应体应该匹配")

			// 验证 mock 预期已满足
			mockOp.AssertExpectations(t)
		})
	}
}
